package cn.catsdad.service.impl;

import cn.catsdad.base.page.PageBean;
import cn.catsdad.base.page.PageParam;
import cn.catsdad.base.service.impl.BaseCrudServiceImpl;
import cn.catsdad.dto.DepartmentDTO;
import cn.catsdad.exception.BaseException;
import cn.catsdad.repository.DepartmentRepository;
import cn.catsdad.service.api.DepartmentService;
import cn.catsdad.service.api.DepartmentUserService;
import cn.catsdad.util.StringUtil;
import cn.catsdad.util.TreeUtil;
import cn.catsdad.vo.TreeNodeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 部门service实现
 *
 * @author xuyonglong
 * @version V1.0 2023/4/12
 */
@Service
public class DepartmentServiceImpl extends BaseCrudServiceImpl<DepartmentDTO, Long, DepartmentRepository>
        implements DepartmentService {

    private DepartmentUserService departmentUserService;

    @Override
    public void pageQuery(PageBean<DepartmentDTO> page, PageParam param) {
        page.setEntityName("DepartmentDTO d");
        page.setQuery("select d");
        super.pageQuery(page, param);
    }

    @Override
    public Set<Long> queryChildrenIds(Long parentId) {
        Set<Long> result = new HashSet<>();
        fillingChildrenIds(result, parentId);
        return result;
    }

    /**
     * 递归填充子级id
     *
     * @param allChildIds 子级集合容器
     * @param parentId    父级id
     */
    private void fillingChildrenIds(Set<Long> allChildIds, Long parentId) {
        allChildIds.add(parentId);
        List<DepartmentDTO> children = repository.findByParentIdIn(Collections.singleton(parentId));
        if (StringUtil.isNotEmpty(children)) {
            Set<Long> childIds = children.stream().map(DepartmentDTO::getId).collect(Collectors.toSet());
            allChildIds.addAll(childIds);
            for (Long childId : childIds) {
                fillingChildrenIds(allChildIds, childId);
            }
        }
    }

    @Override
    public List<TreeNodeVO> queryTree(PageParam param) {
        PageBean<DepartmentDTO> departmentPageBean = new PageBean<>();
        departmentPageBean.setPage(1).setSize(Integer.MAX_VALUE);
        pageQuery(departmentPageBean, param);
        List<DepartmentDTO> departments = departmentPageBean.getQueryResult();
        List<TreeNodeVO> result = new ArrayList<>();
        for (DepartmentDTO department : departments) {
            result.add(department.initTreeNode());
        }
        return TreeUtil.buildTree(result, TreeUtil.Sort.DESC);
    }

    /**
     * 根据用户id查询部门
     *
     * @param userId 用户id
     * @return 部门
     */
    @Override
    public DepartmentDTO queryDepartmentOfUser(Long userId) {
        Long departmentId = departmentUserService.queryDepartmentIdByUserId(userId);
        DepartmentDTO result = null;
        if (departmentId != null) {
            result = queryById(userId);
        }
        return result;
    }

    @Override
    @Transactional
    public DepartmentDTO save(DepartmentDTO entity) {
        validation(entity);
        return super.save(entity);
    }

    /**
     * 唯一性验证
     *
     * @param entity 保存的对象
     */
    private void validation(DepartmentDTO entity) {
        Integer count = repository.countByNameAndIdNotAndIsDeletedFalse(entity.getName(), entity.getId());
        if (count > 0) {
            throw new BaseException("已存在当前部门！");
        }
    }

    /**
     * 重写删除，级联删除子级
     *
     * @param longs 实体keu
     */
    @Override
    @Transactional
    public void logicDeleteByIds(Collection<Long> longs) {
        List<Long> allDeleteList = new ArrayList<>(longs);
        getChildIds(longs, allDeleteList);
        super.logicDeleteByIds(allDeleteList);
    }

    /**
     * 重写删除，级联删除子级
     *
     * @param aLong 实体key
     */
    @Override
    @Transactional
    public void logicDeleteById(Long aLong) {
        List<Long> allDeleteList = new ArrayList<>();
        allDeleteList.add(aLong);
        getChildIds(Collections.singleton(aLong), allDeleteList);
        super.logicDeleteByIds(allDeleteList);
    }

    /**
     * 递归获取子级id
     *
     * @param parentIds 父级id
     * @param allIds    所有id容器
     */
    private void getChildIds(Collection<Long> parentIds, Collection<Long> allIds) {
        if (StringUtil.isNotEmpty(parentIds)) {
            List<DepartmentDTO> children = repository.findByParentIdIn(parentIds);
            if (StringUtil.isNotEmpty(children)) {
                List<Long> childrenIds = children.stream().map(DepartmentDTO::getId).collect(Collectors.toList());
                allIds.addAll(childrenIds);
                getChildIds(childrenIds, allIds);
            }
        }
    }

    @Autowired
    public void setDepartmentUserService(DepartmentUserService departmentUserService) {
        this.departmentUserService = departmentUserService;
    }
}
